package com.autumn.mybatis.criterion;

import java.util.ArrayList;
import java.util.List;

import com.autumn.mybatis.criterion.clauses.OrderClause;
import com.autumn.mybatis.criterion.clauses.PageClause;
import com.autumn.mybatis.criterion.expressions.ColumnExpression;
import com.autumn.mybatis.criterion.impl.QuerySectionImpl;
import com.autumn.mybatis.metadata.EntityColumnOrder;
import com.autumn.mybatis.metadata.EntityTable;
import com.autumn.util.ExceptionUtils;

/**
 * 
 * @author 老码农
 *
 *         2017-10-26 14:41:49
 */
public class Query extends AbstractCriteria<Query> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -9142107239301673713L;

	private PageClause pageClause = null;
	private List<OrderClause> orderClauses = new ArrayList<>();

	/**
	 * 无表实例化
	 */
	public Query() {

	}

	/**
	 * 转入 entityClass 实例化
	 * 
	 * @param entityClass
	 *            实体类型
	 */
	public Query(Class<?> entityClass) {
		super(entityClass);
	}

	/**
	 * 转入 EntityTable 实例化
	 * 
	 * @param entityTable
	 *            实体表
	 */
	public Query(EntityTable entityTable) {
		super(entityTable);
	}

	/**
	 * 重置
	 */
	@Override
	public void reset() {
		super.reset();
		this.pageClause = null;
		this.orderClauses.clear();
	}

	/**
	 * 跳过记录数(相当于调用 limit)
	 * 
	 * @param count
	 *            数量
	 * @return
	 */
	public Query skip(int count) {
		if (this.pageClause == null) {
			this.pageClause = new PageClause(count, 0);
		} else {
			this.pageClause.setOffset(count);
		}
		return this;
	}

	/**
	 * 从开头返回记录数 (相当于调用 limit)
	 * 
	 * @param count
	 *            数量
	 * @return
	 */
	public Query take(int count) {
		if (this.pageClause == null) {
			this.pageClause = new PageClause(0, count);
		} else {
			this.pageClause.setLimit(count);
		}
		return this;
	}

	/**
	 * 分页
	 * 
	 * @param currentPage
	 *            当前页
	 * @param pageSize
	 *            页大小
	 * @return
	 */
	public Query page(int currentPage, int pageSize) {
		if (currentPage < 1) {
			ExceptionUtils.throwArgumentOverflowException("currentPage", "currentPage 不能小于1。");
		}
		if (pageSize < 1) {
			ExceptionUtils.throwArgumentOverflowException("pageSize", "pageSize 不能小于1。");
		}
		int offset = (currentPage - 1) * pageSize;
		return limit(offset, pageSize);
	}

	/**
	 * 分页查询
	 * 
	 * @param offset
	 * @param limit
	 * @return
	 */
	public Query limit(int offset, int limit) {
		if (this.pageClause == null) {
			this.pageClause = new PageClause(offset, limit);
		} else {
			this.pageClause.setOffset(offset);
			this.pageClause.setLimit(limit);
		}
		return this;
	}

	/**
	 * 清除分页
	 * 
	 * @return
	 */
	public Query clearLimit() {
		this.pageClause = null;
		return this;
	}

	/**
	 * 移除排序
	 * 
	 * @param columnName
	 *            列名称
	 */
	private void removeOrder(String columnName) {
		if (this.orderClauses.size() > 0) {
			int index = -1;
			for (int i = 0; i < this.orderClauses.size(); i++) {
				OrderClause clause = this.orderClauses.get(i);
				if (clause.getColumnName().equalsIgnoreCase(columnName)) {
					index = i;
					break;
				}
			}
			if (index >= 0) {
				this.orderClauses.remove(index);
			}
		}
	}

	/**
	 * 排序
	 * 
	 * @param name
	 *            属性或列名称
	 * @param direction
	 *            排序方向
	 * @return
	 */
	public Query order(String name, OrderDirectionEnum direction) {
		ExceptionUtils.checkNotNull(direction, "direction");
		ColumnExpression col = column(name);
		removeOrder(col.getColumnName());
		OrderClause clause = new OrderClause(col.getColumnName(), direction.getValue());
		this.orderClauses.add(clause);
		return this;
	}

	/**
	 * 获取排序列数
	 * 
	 * @return
	 */
	public int getOrderColumns() {
		return this.orderClauses.size();
	}

	/**
	 * 采用表默认排序(如果表配置有默认排序)
	 * 
	 * @return
	 */
	public Query orderDefault() {
		if (this.getEntityTable() != null && this.getEntityTable().getOrderColumns() != null
				&& this.getEntityTable().getOrderColumns().size() > 0) {
			for (EntityColumnOrder orderClause : this.getEntityTable().getOrderColumns()) {
				removeOrder(orderClause.getColumn().getColumnName());
				OrderClause clause = new OrderClause(orderClause.getColumn().getColumnName(),
						orderClause.getDirection().toString());
				this.orderClauses.add(clause);
			}
		}
		return this;
	}

	/**
	 * 升序
	 * 
	 * @param name
	 *            属性或列名称
	 * @return
	 */
	public Query orderBy(String name) {
		return order(name, OrderDirectionEnum.ASC);
	}

	/**
	 * 降序
	 * 
	 * @param name
	 *            属性或列名称
	 * @return
	 */
	public Query orderByDescending(String name) {
		return order(name, OrderDirectionEnum.DESC);
	}

	/**
	 * 清除排序
	 * 
	 * @return
	 */
	public Query clearOrder() {
		this.orderClauses.clear();
		return this;
	}

	/**
	 * 
	 * @param qs
	 */
	protected void setQuerySection(IQuerySection qs) {
		// 排序
		if (this.orderClauses.size() > 0) {
			qs.getOrderClauses().addAll(this.orderClauses);
		}
		// 分页
		if (this.pageClause != null) {
			qs.getPageClause().setOffset(this.pageClause.getOffset());
			qs.getPageClause().setLimit(this.pageClause.getLimit());
		}
	}

	/**
	 * 生成
	 * 
	 * @return
	 */
	@Override
	public IQuerySection builderSection() {
		QuerySectionImpl qs = new QuerySectionImpl(this.lockMode);
		// 条件表达式
		qs.getCriterias().addAll(this.createCriteriaSections());
		this.setQuerySection(qs);
		return qs;
	}

}
